package org.chene.elastic.service;

import java.io.IOException;
import java.util.List;

import org.chene.elastic.annotation.EsKey;
import org.chene.elastic.bean.EsTypeInfo;
import org.chene.elastic.bean.UpdatableDocument;
import org.chene.elastic.client.EsClientManager;
import org.chene.elastic.util.AnnotationUtil;
import org.chene.elastic.util.MappingUtil;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.admin.indices.exists.types.TypesExistsRequest;
import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequest;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.update.UpdateRequestBuilder;
import org.elasticsearch.client.transport.TransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;

@Service
public class IndexService {

	private static final Logger LOGGER = LoggerFactory.getLogger(IndexService.class);

	@Autowired
	private EsClientManager clientManager;

	public void save(String index, Object... docs) {
		// 判断索引是否存在，不存在则创建索引
		if (!isIndexExists(index)) {
			createIndex(index);
		}

		if (null != docs) {
			BulkRequestBuilder requestBuilder = clientManager.getClient().prepareBulk();
			try {
				for (Object document : docs) {
					EsTypeInfo esType = MappingUtil.analyze(index, clientManager.getClient(), document);
					List<Object> beans = MappingUtil.listBean(esType, document);

					for (Object bean : beans) {
						appendDocument(index, requestBuilder, bean);
					}
				}
				requestBuilder.execute().actionGet();
			} catch (ElasticsearchException e) {
				LOGGER.error("保存文档异常", e);
				throw e;
			} catch (IllegalArgumentException e) {
				LOGGER.error("保存文档异常", e);
				throw e;
			} catch (IllegalAccessException e) {
				LOGGER.error("保存文档异常", e);
				throw new RuntimeException(e);
			} catch (IOException e) {
				LOGGER.error("保存文档异常", e);
				throw new RuntimeException(e);
			}
		}
	}

	private void appendDocument(String index, BulkRequestBuilder requestBuilder, Object document)
			throws IllegalAccessException {
		requestBuilder.add(clientManager
				.getClient()
				.prepareIndex(index, document.getClass().getSimpleName(),
						String.valueOf(AnnotationUtil.getFieldValueByAnnotation(document, EsKey.class)))
				.setSource(JSON.toJSONString(document)));
	}

	public void update(String index, UpdatableDocument... docs) {
		BulkRequestBuilder requestBuilder = clientManager.getClient().prepareBulk();

		for (UpdatableDocument updatableDocument : docs) {
			UpdateRequestBuilder updateRequestBuilder = clientManager.getClient().prepareUpdate(index,
					updatableDocument.getDocType().getSimpleName(), updatableDocument.getId());

			updateRequestBuilder.setDoc(updatableDocument.getValues());
			requestBuilder.add(updateRequestBuilder);
		}

		BulkResponse response = requestBuilder.execute().actionGet();
		if (response.hasFailures()) {
			LOGGER.error("更新单个文档的指定字段异常: " + response.buildFailureMessage());
		}
	}

	public void delete(String index, Object... docs) {
		if (null == docs) {
			return;
		}

		try {
			for (Object document : docs) {
				clientManager
						.getClient()
						.prepareDelete(index, document.getClass().getSimpleName(),
								String.valueOf(AnnotationUtil.getFieldValueByAnnotation(document, EsKey.class)))
						.execute().actionGet();
			}
		} catch (ElasticsearchException e) {
			LOGGER.error("删除文档异常", e);
			throw e;
		} catch (IllegalArgumentException e) {
			LOGGER.error("删除文档异常", e);
			throw e;
		} catch (IllegalAccessException e) {
			LOGGER.error("删除文档异常", e);
			throw new RuntimeException(e);
		}
	}

	/**
	 * 判断类型是否存在
	 *
	 * @param index
	 * @param type
	 * @return
	 */
	public boolean isTypeExist(String index, String type) {
		return clientManager.getClient().admin().indices()
				.typesExists(new TypesExistsRequest(new String[] { index }, type)).actionGet().isExists();
	}

	/**
	 * 删除类型
	 *
	 * @param index
	 * @param type
	 * @return
	 */
	public void deleteTypes(String index, String... types) {
		clientManager.getClient().admin().indices().deleteMapping(new DeleteMappingRequest(index).types(types))
				.actionGet();
	}

	/**
	 * 验证索引是否已经存在
	 *
	 * @param indice
	 *            索引
	 * @return
	 */
	public boolean isIndexExists(String indice) {
		TransportClient transportClient = clientManager.getClient();
		IndicesExistsRequest existsRequest = new IndicesExistsRequest(indice);
		IndicesExistsResponse response = transportClient.admin().indices().exists(existsRequest).actionGet();
		return response.isExists();
	}

	/**
	 * 创建索引
	 * 
	 * @param index
	 */
	public void createIndex(String index) {
		clientManager.getClient().admin().indices().prepareCreate(index).execute().actionGet();
	}

	/**
	 * 删除索引
	 *
	 * @param index
	 *            索引
	 * @return
	 */
	public boolean deleteIndex(String index) {
		TransportClient transportClient = clientManager.getClient();
		transportClient.admin().indices().prepareDelete(index).execute().actionGet();
		return true;
	}
}
